package com.zkq.graduate.service.impl;

import com.mongodb.client.result.UpdateResult;
import com.zkq.graduate.pojo.StudentVo;
import com.zkq.graduate.pojo.StudentWithReport;
import com.zkq.graduate.service.MongoDbService;
import com.zkq.graduate.service.SelectedTitleService;
import com.zkq.graduate.service.StudentService;
import com.zkq.graduate.util.FileUtil;
import com.zkq.graduate.util.LocalDateTimeUtil;
import com.zkq.graduate.util.MD5Util;
import com.zkq.graduate.util.ResultHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Field;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.zkq.graduate.util.FileUtil.fileType;

/**
 * @Author zhangkaiqiang
 * @Date 2019/12/12  16:44
 * @Description TODO
 */
@Service("mongoService")
@Slf4j
@PropertySource(value = {"classpath:config/application-dev.properties"})
public class MongoDbServiceImpl implements MongoDbService {


	/**
	 * 开题报告和毕业论文的状态码
	 */
	private final static int OPEN=1;

	private final static int PAPER=2;

	/**
	 * 开题报告集合名称
	 */
	@Value("${mongo.openCollectionName}")
	private String openCollectionName;

	/**
	 * 毕业论文集合名称
	 */
	@Value("${mongo.paperCollectionName}")
	private String paperCollectionName;

	@Autowired
	private MongoTemplate mongoTemplate;

	@Resource(name = "studentService")
	private StudentService studentService;

    @Resource(name = "selectedTitleService")
	private SelectedTitleService selectedTitleService;

	@Override
	public Map<String,String> insertStudentPaper(HttpServletRequest request, MultipartFile file,String flag) {

		Map<String,String> resultMap=new HashMap<>();
		// 得到写入到mongo中的信息
		String studentId= (String) request.getAttribute("account");
		String studentName=studentService.findByStudentId(studentId).map(item->item.getStudentName()).orElse("");
		byte[] fileContext= FileUtil.getMultipartFileByte(file);
		String fileName=FileUtil.getFileName(file,studentId,studentName,flag);
		String md5File= MD5Util.mD5Encode(new String(fileContext));


		// 根据文件内容的md5值检测文件是否已经存在
		Criteria criteria= Criteria.where("md5").is(md5File);
		Query query = Query.query(criteria);
		List<StudentWithReport> list=new ArrayList<>();
		if(OPEN== fileType(fileName)){
			list=mongoTemplate.find(query,StudentWithReport.class,openCollectionName);
		} else if(PAPER==fileType(fileName)){
			list=mongoTemplate.find(query,StudentWithReport.class,paperCollectionName);
		}
		if(list.size()>0){
			resultMap.put("code","-1");
			resultMap.put("msg","file is exists");
			return resultMap;
		}

		// 查找该学生选择的题目信息并保存到Mongo中
		List<StudentVo> selectList=selectedTitleService.findStudentSelectedTitle(studentId);
		StudentVo studentVo=new StudentVo();
		for(StudentVo st:selectList){
			if(Objects.equals("达成双选",st.getSelectStatus())){
				studentVo=st;
			}
		}

		// 置入到mongodb中的数据
		StudentWithReport studentWithReport=StudentWithReport.builder()
				.studentId(studentId)
				.fileName(fileName)
				.fileContext(fileContext)
				.md5(md5File)
				.status("待审核")
				.title(studentVo.getTitle())
				.uploadTime(LocalDateTimeUtil.getStringNow())
				.isLast(true)
				.build();

		// 更新集合中已经上传的数据
		Map<String,Object> updateCondition=new HashMap();
		updateCondition.put("studentId",studentId);
		StudentWithReport temp=StudentWithReport.builder()
				.studentId(studentId)
				.isLast(false)
				.build();

		// 根据是开题报告还是毕业论文,保存到不同的集合
		if(OPEN==fileType(fileName)){
			// 更新集合中该学生已经上传的文档为非最新记录
			updateFileByAddition(updateCondition,temp,"open");
			mongoTemplate.insert(studentWithReport,openCollectionName);
			log.debug(studentId+">>>>>>上传了开题报告文档");
		} else if (PAPER==fileType(fileName)){
			updateFileByAddition(updateCondition,temp,"paper");
			mongoTemplate.insert(studentWithReport,paperCollectionName);
			log.debug(studentId+">>>>>上传了毕业论文");
		}
		resultMap.put("code","0");
		resultMap.put("msg","success");
		return resultMap;
	}

	@Override
	public Optional<StudentWithReport> findLastStudentPaper(String studentId, String flag,List<String> fields) {
		Map<String,Object> map=new LinkedHashMap<>();
		map.put("studentId",studentId);
		return findStudentPaper(map,flag,fields).stream().findFirst();
	}

	@Override
	public List<StudentWithReport> findStudentPaper(Map<String,Object> findAddtion,String flag,List<String> fields) {
		List<StudentWithReport> resultList=new LinkedList<>();
		List<StudentWithReport> openList=new LinkedList<>();
		List<StudentWithReport> paperList=new LinkedList<>();
		if(findAddtion.size()!=0){
			// 设定查询条件
			Criteria criteria = setQueryCondition(findAddtion);
			Query query = Query.query(criteria);
			query.with(new Sort(new Sort.Order(Sort.Direction.DESC,"uploadTime")));

			// 设定查询的列--未设定时查询全部列
			Field findFields = query.fields();
			if(!CollectionUtils.isEmpty(fields)){
				fields.forEach(findFields::include);
			} else {
				fields.add("studentId");
				fields.add("fileName");
				fields.add("fileContext");
				fields.add("uploadTime");
				fields.add("status");
				fields.add("title");
				fields.add("md5");
				fields.add("isLast");
				fields.forEach(findFields::include);
			}

			if(Objects.equals("open",flag)){
				openList=mongoTemplate.find(query,StudentWithReport.class,openCollectionName);
			} else if(Objects.equals("paper",flag)){
				paperList=mongoTemplate.find(query,StudentWithReport.class,paperCollectionName);
			} else{
				openList=mongoTemplate.find(query,StudentWithReport.class,openCollectionName);
				paperList=mongoTemplate.find(query,StudentWithReport.class,paperCollectionName);
			}
		}

		if(openList!=null && openList.size()>0){
			resultList.addAll(openList);
		}
		if(paperList!=null && paperList.size()>0){
			resultList.addAll(paperList);
		}
		return resultList;
	}

	 @Override
		public ResultHandler<Page> findStudentPaperWithPaging(
			Map<String, Object> findAddtion,
			String flag,
			int currentPage,
			int pageSize,
			List<String> fields) {

		Pageable pageable =PageRequest.of(currentPage,pageSize);
		List<StudentWithReport> studentList=findStudentPaper(findAddtion,flag,fields);
		long total=getTotal(findAddtion,flag);
		Page<StudentWithReport> studentPage = new PageImpl(studentList, pageable, total);
		ResultHandler<Page> resultHandler=new ResultHandler(studentPage);
		resultHandler.setCount((int)total);
		return resultHandler;
	}

	@Override
	public int updateFileByAddition(Map<String,Object> updateAddtion,StudentWithReport student,String flag) {
		Criteria criteria = setQueryCondition(updateAddtion);
		UpdateResult result=null;
		Query query=Query.query(criteria);
		Update update = new Update();
		update.set("isLast",student.isLast());
		// 判断这些内容是否为空,不为空进行数据的更新
		if(student.getFileContext()!=null){
			update.set("fileContext",student.getFileContext());
		}
		if(StringUtils.isNotBlank(student.getStatus())){
			update.set("status",student.getStatus());
		}
		if(StringUtils.isNotBlank(student.getMd5())){
			update.set("md5",MD5Util.mD5Encode(new String(student.getFileContext())));
		}

		// 进行判断,操作不同的collection
		if(Objects.equals("open",flag)){
			result=mongoTemplate.updateMulti(query,update,openCollectionName);
		} else if(Objects.equals("paper",flag)){
			result=mongoTemplate.updateMulti(query,update,paperCollectionName);
		}
		return (int) result.getMatchedCount();
	}

	@Override
	public long getTotal(Map<String, Object> findAddtion, String flag) {
		Criteria criteria = setQueryCondition(findAddtion);
		Query query=new Query(criteria);
		long count=0;
		if(Objects.equals("open",flag)){
			count=mongoTemplate.count(query,openCollectionName);
		} else if(Objects.equals("paper",flag)){
			count=mongoTemplate.count(query,paperCollectionName);
		}
		return count;
	}


	/**
	 * 设定查询条件
	 * @param findAddtion
	 * @return
	 */
	private Criteria setQueryCondition(Map<String,Object> findAddtion){
		Criteria criteria = new Criteria();
		Set<Map.Entry<String,Object>> entries=findAddtion.entrySet();
		Iterator it=entries.iterator();
		while(it.hasNext()){
			Map.Entry<String,Object> entry= (Map.Entry<String, Object>) it.next();
			criteria.and(entry.getKey()).is(entry.getValue());
		}
		return criteria;
	}
}